package com.kinroy.reggie.controller;

import com.kinroy.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;

@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
    /*这个controller用来处理从网页中传来的文件，这个文件会变成流的形式传过来，
     * 我们在这里对这个文件流来进行处理，实现在新增菜品逻辑时，能够把菜品的图片从页面传到
     * 我们web服务中。
     *
     * 在这里说几个细节，就是上传  upload  操作中，发来的请求必须是post请求，同时我们服务器端
     * 接收到上传的文件，在底层中用来实现处理的是用到 apache 开发的 common-fileupload 和 common-io
     * 这两个组件，但是呢，我们自己去使用这个两个组件来实现 upload 操作会相对复杂，spring-web包
     * 中已经帮我把这些操作进行了封装，我们只需 用一个 MultpartFile 类来接收即可
     * */
    @Value("${reggie.savePath}")
    private String savePath;

    /*网页上传文件到服务端保存功能*/
    @PostMapping(value = "/upload")
    public R<String> upload(MultipartFile file) {
        /*我们用来接收上传数据的这个 MultipartFile file 是一个临时文件，同时参数名不能写别的，
        前端的请求中已经约定好了是file，不然会接收不到数据的
        * 当我们这一次上传操作完成后，就会自动删除
        * */

        /*MultipartFile 对象中封装了一个方法，就是transferTo（保存的路径），能够将获取到上传的文件数据流
         * 变回原来的文件，并且保存到我们所指定的位置,而这个保存的位置，为了之后上线后能更好的统一更改，这里就写在了yml
         * 配置文件中，然后通过Di注入到我们的这个controller里
         * */
        String originalFilename = file.getOriginalFilename();
        log.info("获取到的原文件名为：{}", originalFilename);
        /*调用substring方法进行截取文件的后缀名*/
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));


        /*同时我们可以用uuid来给上传的文件起名，这样就不会出现上传文件重名而存不了的情况*/
        String fileName = UUID.randomUUID().toString() + suffix;
        log.info("通过uuid生成的文件全称为{}", fileName);
        try {
            file.transferTo(new File(savePath + fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("网页上传的图片的数据流为{}", file.toString());
        /*我们返回文件名的意义是，在新增菜品时，图片上传完成后也要把文件名存在菜品的实体属性中去的，所以把文件名传回去*/
        return R.success(fileName);
    }

    /*网页从服务端下载图片显示功能*/
    @GetMapping("/download")
    public void download( String name, HttpServletResponse response) throws IOException {
        /*上传图片完成后，前端便会在发送一个请求来让我服务端把刚才上传的图片进行显示
         * 我们相应这个显示的请求时，不需要返回值，只需要通过response响应输出流向浏览器页面写回数据
         * */
        try {
            /*输入流，通过输入流读取文件内容*/
            FileInputStream fileInputStream = new FileInputStream(new File(savePath + name));
            /*输出流，写回浏览器*/
            ServletOutputStream outputStream = response.getOutputStream();
            /*我们通过写回的方式是，输入流读一行，输出流输出一行，当输入流读完时，输出流也输出完成了，*/
            int len = 0;
            byte[] bytes = new byte[1024];
            /*如何理解输入流的read方法和输出流的write方法呢？
            * 输入流的read（）中传入一个byte数组，读完一行后，将这一行的字节流存入这个byte数组中，同时该方法的返回值是
            * 还有几行字节流没有读取
            *
            * 输出流的write（）方法中传入形参有，要输出的字节数组，和从哪一行开始输出，到哪一行结束输出
            * */
            while ((len=fileInputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
                /*刷新一下*/
                outputStream.flush();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}
